<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>补充-手写apply-call抽取封装</title>
</head>
<body>

  <script>
    // new Function()
    // foo.__proto__ === Function.prototype
    function foo(name, age) {
      console.log(this, name, age)
      return 'foo'
    }

    function execFn(fn, thisArg, otherArgs) {
      thisArg = thisArg || window

      thisArg.fn = fn

      thisArg = (thisArg === null || thisArg === undefined) ? window : Object(thisArg)

      Object.defineProperty(thisArg, 'fn', {
        configurable: true,
        enumerable: false,
        writable: true,
        value: fn
      })

      const result = thisArg.fn(...otherArgs)

      delete thisArg.fn

      return result
    }

    const result = execFn(foo, {name: 'execFn', age: 18}, ['exec', 30])
    console.log(result);

    Function.prototype.createExec = function (thisArg, otherArgs) {
      thisArg = thisArg || window

      thisArg.fn = this

      thisArg = (thisArg === null || thisArg === undefined) ? window : Object(thisArg)

      Object.defineProperty(thisArg, 'fn', {
        configurable: true,
        enumerable: false,
        writable: true,
        value: this
      })

      const result = thisArg.fn(...otherArgs)

      delete thisArg.fn

      return result
    }

    Function.prototype.createApply = function (thisArg, otherArgs) {
      return this.createExec(thisArg, otherArgs)
    }

    Function.prototype.createCall = function (thisArg, ...otherArgs) {
      return this.createExec(thisArg, otherArgs)
    }

    const result1 = foo.createCall({name: 'createCall', age: 18}, 'Call', 30)
    const result2 = foo.createApply({name: 'createApply', age: 18}, ['apply', 30])
    console.log(result1, result2);
    
    
  </script>
  
</body>
</html>